package graph.util;

import java.util.ArrayList;
import java.util.List;
import java.io.*;

import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLReaderWriter {
	private String xmlFileName;
	private AutomatonInfo info;
	
	public XMLReaderWriter() {
		this.xmlFileName = new String();
		this.info = new AutomatonInfo();
	}
	
	public String getXmlFileName() {
		return xmlFileName;
	}

	public AutomatonInfo getInfo() {
		return info;
	}

	public void setXmlFileName(String xmlFileName) {
		this.xmlFileName = xmlFileName;
	}

	public void setInfo(AutomatonInfo info) {
		this.info = info;
	}

	public void readXMLFile(String fileName) {
		try {
			File file = new File(fileName);
			xmlFileName = fileName;
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(file);
			doc.getDocumentElement().normalize();

			//Get states
			info.setStates(getElement(doc, "states", "state"));

			//Get inputs
			info.setInputs(getElement(doc, "inputs", "label"));
			
			//Get initial states
			info.setInitialStates(getElement(doc, "initialstates", "state"));

			//Get final states
			info.setFinalStates(getElement(doc, "finalstates", "state"));
			
			//Get transitions
			List<String[]> transitions = new ArrayList<String[]>();
			NodeList nodeLstTransitions = doc.getElementsByTagName("transitions");
			for (int i = 0; i < nodeLstTransitions.getLength(); i++) {
				Node fstNode = nodeLstTransitions.item(i);

				if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
					Element fstElmnt = (Element) fstNode;

					//first state
					ArrayList<String> firstStates = new ArrayList<String>();
					NodeList fstStateElmntLst = fstElmnt.getElementsByTagName("firststate");
					for (int x = 0; x < fstStateElmntLst.getLength(); x++) {
						Element stateElmnt = (Element) fstStateElmntLst.item(x);
						NodeList state = stateElmnt.getChildNodes();
						for (int y = 0; y < state.getLength(); y++) {
							firstStates.add((state.item(y)).getNodeValue());
						}
					}

					//last state
					ArrayList<String> lastStates = new ArrayList<String>();
					NodeList lstStateElmntLst = fstElmnt.getElementsByTagName("laststate");
					for (int x = 0; x < lstStateElmntLst.getLength(); x++) {
						Element stateElmnt = (Element) lstStateElmntLst.item(x);
						NodeList state = stateElmnt.getChildNodes();
						for (int y = 0; y < state.getLength(); y++) {
							lastStates.add((state.item(y)).getNodeValue());
						}
					}

					//Get label
					ArrayList<String> labels = new ArrayList<String>();
					NodeList labelElmntLst = fstElmnt.getElementsByTagName("label");
					for (int x = 0; x < labelElmntLst.getLength(); x++) {
						Element labelElmnt = (Element) labelElmntLst.item(x);
						NodeList label = labelElmnt.getChildNodes();
						for (int y = 0; y < label.getLength(); y++) {
							labels.add((label.item(y)).getNodeValue());
						}
					}
					
					//Create transitions
					for(int x = 0; x < labels.size(); x++) {
						String[] transition = new String[3];
						transition[0] = firstStates.get(x);
						transition[1] = labels.get(x);
						transition[2] = lastStates.get(x);
						transitions.add(transition);
					}
				}
			}
			info.setTransitions(transitions);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private List<String> getElement(Document doc, String nodeName, String childNodeName) {
		List<String> ret = new ArrayList<String>();
		
		NodeList nodeLst = doc.getElementsByTagName(nodeName);
		for (int i = 0; i < nodeLst.getLength(); i++) {
			Node fstNode = nodeLst.item(i);

			if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
				Element fstElmnt = (Element) fstNode;
				NodeList elmntLst = fstElmnt.getElementsByTagName(childNodeName);
				for (int j = 0; j < elmntLst.getLength(); j++) {
					Element elmnt = (Element) elmntLst.item(j);
					NodeList childNodes = elmnt.getChildNodes();
					for (int k = 0; k < childNodes.getLength(); k++) {
						ret.add((childNodes.item(k)).getNodeValue());
					}
				}
			}
		}
		
		return ret;
	}

	public void writeXMLFile(String fileName) {
		try {
			OutputStream fout= new FileOutputStream(fileName);
			xmlFileName = fileName;
			OutputStream bout= new BufferedOutputStream(fout);
			OutputStreamWriter out = new OutputStreamWriter(bout);
			List<String> states = info.getStates();
			List<String> inputs = info.getInputs();
			List<String[]> transitions = info.getTransitions();
			List<String> initialStates = info.getInitialStates();
			List<String> finalStates = info.getFinalStates();
			
			out.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
			out.write("<automata>\n");
			
			//states
			out.write("\t<states>\n");
			for (String state : states) {
				out.write("\t\t<state>" + state + "</state>\n");
			}
			out.write("\t</states>\n");
			
			//inputs
			out.write("\t<inputs>\n");
			for (String input : inputs) {
				out.write("\t\t<label>" + input + "</label>\n");
			}
			out.write("\t</inputs>\n");
			
			//transitions
			out.write("\t<transitions>\n");
			for (String[] transition : transitions) {
				out.write("\t\t<transition>\n");
				out.write("\t\t\t<firststate>" + transition[0] + "</firststate>\n");
				out.write("\t\t\t<label>" + transition[1] + "</label>\n");
				out.write("\t\t\t<laststate>" + transition[2] + "</laststate>\n");
				out.write("\t\t</transition>\n");
			}
			out.write("\t</transitions>\n");
			
			//initial states
			out.write("\t<initialstates>\n");
			for (String initialState : initialStates) {
				out.write("\t\t<state>" + initialState + "</state>\n");
			}
			out.write("\t</initialstates>\n");
			
			//final states
			out.write("\t<finalstates>\n");
			for (String finalState : finalStates) {
				out.write("\t\t<state>" + finalState + "</state>\n");
			}
			out.write("\t</finalstates>\n");
			
			out.write("</automata>\n"); 

			out.flush();
			out.close();
		} catch (IOException e) {
			System.out.println(e.getMessage());
		}
	}
	
	public void printAutomaton() {
		String str = "";
		List<String> states = info.getStates();
		List<String> inputs = info.getInputs();
		List<String[]> transitions = info.getTransitions();
		List<String> initialStates = info.getInitialStates();
		List<String> finalStates = info.getFinalStates();
		
		//states
		str += "States = {";
		for (String state : states) {
			str += state + " ";
		}
		str += "}\n";
		
		//inputs
		str += "Inputs = {";
		for (String input : inputs) {
			str += input + " ";
		}
		str += "}\n";
		
		//transitions
		str += "Transitions = {";
		for (String[] transition : transitions) {
			str += "(" + transition[0] + " " + transition[1] + " " + transition[2] + ") ";
		}
		str += "}\n";
		
		//initial states
		str += "Initial states = {";
		for (String initialState : initialStates) {
			str += initialState + " ";
		}
		str += "}\n";
		
		//last states
		str += "Final states = {";
		for (String finalState : finalStates) {
			str += finalState + " ";
		}
		str += "}\n";
		System.out.println(str);
		JOptionPane.showMessageDialog(null, str);
	}
}
